package com.zxiw.zxedu.datasync

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import java.util.*

/**
 * @author zhangxiaoming
 * @date 2023/8/9
 * @description
 */
data class XTask(
    val name: String,//任务名称，不可以重复
    val desc: String = "",//任务描述
    val coroutineDispatcher: CoroutineDispatcher = Dispatchers.Default,//线程调度
    val priority: Int = 0,   // 运行的优先级，值小的先执行,
    var dependentTasks: Set<String> = setOf(), // 依赖的任务集合(不可重复，所以用Set)
    val run: suspend () -> Boolean = { false }, //具体的执行任务的函数，为什么放在构造函数，主要是方便全局查看任务。返回是否拦截
) : Observable(){
    // 入度，用于有向无环图的拓扑排序
    var inDegree = dependentTasks.size

    /**
     * 通知通知观察者
     */
    fun notify(arg: Any) {
        setChanged()
        notifyObservers(arg)
    }

    /**
     * 构造任务集
     * @param tasks Array<out XTask>
     * @return MutableSet<String>
     */
    fun on(vararg tasks: XTask): MutableSet<XTask> {
        val dependentTasks = mutableSetOf<XTask>()
        if (tasks.isNotEmpty()) {
            for (task in tasks) {
                dependentTasks.add(task)
            }
        }
        return dependentTasks
    }

    /**
     * 设置当前任务依赖的任务集
     * @param tasks Set<XTask>
     * @return XTask
     */
    infix fun depends(tasks: Set<XTask>): XTask {
        if (tasks.isNotEmpty()) {
            val dependentTasks = mutableSetOf<String>()
            for (task in tasks) {
                dependentTasks.add(task.name)
            }
            this.dependentTasks = dependentTasks
            this.inDegree = this.dependentTasks.size
        }
        return this
    }

    /**
     * 设置当前任务依赖的任务集
     * @param block [@kotlin.ExtensionFunctionType] Function1<XTask, MutableSet<String>>
     * @return String 返回任务名称
     */
    fun depends(block: XTask.() -> MutableSet<XTask>): XTask {
        val tasks = block()
        if (tasks.isNotEmpty()) {
            val dependentTasks = mutableSetOf<String>()
            for (task in tasks) {
                dependentTasks.add(task.name)
            }
            this.dependentTasks = dependentTasks
            this.inDegree = this.dependentTasks.size
        }
        return this
    }
}

fun <T> on(vararg elements: T): Set<T> = if (elements.isNotEmpty()) elements.toSet() else emptySet()